﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#pragma warning disable 0659

namespace ParserCore
{

    // Statement, ili iskaz, predstavlja jednu Matlab komandu
    public abstract class Statement : IVisited
    {
        protected Statement()
        { }

        public abstract void Accept(IVisitor visitor);

        public sealed override string ToString()
        {
            var visitor = new ToStringVisitor();
            return visitor.GetString(this);
        }


		public sealed override bool Equals(object obj)
		{
			var visitor = new EqualsVisitor();
			return visitor.IsEqual(this, obj);
		}

        // public bool PrintFlag { get; set; }
    }

    // Primer:
    //   u Matlabu : 1 + x
    //   ovde      : new SingleExpressionStatement( new Call(new Identifier("+"), new Constant("1"), new Identifier("x)) )
    public class SingleExpressionStatement : Statement
    {
        public Expression Expr { get; private set; }

        public SingleExpressionStatement(Expression expr)
            : base()
        {
            Expr = expr;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }
  

    // Primer:
    //   u Matlabu : x = 3
    //   ovde      : new AssignmentStatement(new Identifier("x"), new Constant("3"))
    public class AssignmentStatement : Statement
    {
        public Expression[] LeftHandSide { get; private set; } 
        public Expression RightHandSide { get; private set; }

        public AssignmentStatement(Expression[] lhs, Expression rhs)
            : base()
        {
            LeftHandSide = lhs;
            RightHandSide = rhs;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    // Primer za BlockStatement je dat nize, u okviru primera za IfThenElseStatement
    public class BlockStatement : Statement
    {
        public Statement[] StatementList { get; private set; }

        public BlockStatement(params Statement[] statlist)
            : base()
        {
            StatementList = statlist;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public abstract class ConditionalStatement : Statement
    {
        protected ConditionalStatement()
            : base()
        { }
    }

    // Primer:
    //   u Matlabu :  if x == 3
    //                  a = 4
    //                  b = 5
    //                end
    //   ovde      :  new IfThenElseStatement(
    //                    new Call(new Identifier("=="), new Identifier("x"), new Constant("3")),
    //                    new BlockStatement(
    //                        new AssignmentStatement(new Identifier("a"), new Constant("4")),
    //                        new AssignmentStatement(new Identifier("b"), new Constant("5"))
    //                        ),
    //                    new BlockStatement()
    //                    );
    public class IfThenElseStatement : ConditionalStatement
    {
        public Expression Condition { get; private set; }
        public Statement IfConditionTrueStatement { get; private set; }
        public Statement IfConditionFalseStatement { get; private set; }

        public IfThenElseStatement(Expression cond, Statement iftrue, Statement iffalse)
            : base()
        {
            Condition = cond;
            IfConditionTrueStatement = iftrue;
            IfConditionFalseStatement = iffalse;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }


    // Primer:
    //   u Matlabu : switch x
    //                  case 1 + 2  % potpuno legalno u Matlabu
    //                     n = 0
    //                  case 4
    //                     n = 1
    //                  otherwise
    //                     n = -1
    //               end
    //   ovde      : new SwitchCaseStatement(
    //                   new Identifier("x"),
    //                   new AssignmentStatement(new Identifier("n"), new Constant("-1")),
    //                   new Tuple<Expression, Statement>( 
    //                       new Call(new Identifier("+"), new Constant("1"), new Constant("2")),
    //                       new BlockStatement(
    //                           new AssignmentStatement(new Identifier("n"), new Constant("0"))
    //                           )
    //                       ),
    //                   new Tuple<Expression, Statement>(
    //                       new Constant("4"),
    //                       new BlockStatement(
    //                           new AssignmentStatement(new Identifier("n"), new Constant("1"))
    //                           )
    //                       )
    //                   )
    public class SwitchCaseStatement : ConditionalStatement
    {
        public Expression Expr { get; private set; }
        public Tuple<Expression, Statement>[] Cases { get; private set; }
        public Statement Otherwise { get; private set; }

        public SwitchCaseStatement(Expression expr, Statement otherwise, params Tuple<Expression, Statement>[] cases)
            : base()
        {
            Expr = expr;
            Cases = cases;
            Otherwise = otherwise;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public abstract class LoopStatement : Statement
    {
        public LoopStatement()
            : base()
        { }
    }


    // Primer:
    //   u Matlabu : for k = A
    //                   x = x + k;
    //               end
    //   ovde      : new ForStatement(
    //                   new Identifier("k"),
    //                   new Identifier("A"),
    //                   new BlockStatement(
    //                       new AssignmentStatement(
    //                           new Identifier("x"),
    //                           new Call(new Identifier("+"), new Identifier("x"), new Identifier("k")
    //                           )
    //                       )
    //                   )
    public class ForStatement : LoopStatement
    {
        public Identifier ID { get; private set; }
        public Expression Expr { get; private set; }
        public Statement LoopStatement { get; private set; }

        public ForStatement(Identifier id, Expression expr, Statement loopStatement)
            : base()
        {
            ID = id;
            Expr = expr;
            LoopStatement = loopStatement;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    // Primer:
    //   u Matlabu : while x > 0
    //                  x = x - 1
    //               end
    //   ovde      : new WhileStatement(
    //                   new Call(new Identifier(">"), new Identifier("x"), new Constant("0")),
    //                   new BlockStatement(
    //                       new AssignmentStatement(new Identifier("x"), new Call(new Identifier("-"), new Identifier("x"), new Constant("1")))
    //                       )
    //                   )
    public class WhileStatement : LoopStatement
    {
        public Expression Condition { get; private set; }
        public Statement LoopStatement { get; private set; }

        public WhileStatement(Expression condition, Statement loopStatement)
            : base()
        {
            Condition = condition;
            LoopStatement = loopStatement;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public abstract class LoopControlStatement : Statement
    {
        public LoopControlStatement()
            : base()
        { }
    }

    public class ContinueStatement : LoopControlStatement
    {
        // private LoopStatement Loop { get; set; }

        public ContinueStatement()
            : base()
        { }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }
 


    public class BreakStatement : LoopControlStatement
    {
        // private LoopStatement Loop { get; set; }

        public BreakStatement()
            : base()
        { }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }


    // Primer:
    //   u Matlabu : try
    //                 fun(5)
    //               catch e
    //                 e
    //               end
    //   ovde      : new TryCatchStatement(
    //                   new BlockStatement(
    //                       new SingleExpressionStatement(
    //                           new Call(new Identifier("fun"), new Constant("5"))
    //                           )
    //                       ),
    //                   new Identifier("e"),
    //                   new BlockStatement(
    //                       new SingleExpressionStatement(
    //                           new Identifier("e")
    //                           )
    //                       )
    //                   )
    public class TryCatchStatement : Statement
    {
        public Statement TryStatement { get; private set; }
        public Statement CatchStatement { get; private set; }
        public Identifier CaughtID { get; private set; }

        public TryCatchStatement(Statement tryStatement, Identifier caughtID, Statement catchStatement)
            : base()
        {
            TryStatement = tryStatement;
            CatchStatement = catchStatement;
            CaughtID = caughtID;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class ReturnStatement : Statement
    {
        public ReturnStatement()
            : base()
        { }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class FunctionDefinitionStatement : Statement
    {
        public Identifier[] ReturnList { get; private set; }
        public Identifier[] ParameterList { get; private set; }
        public Identifier FcnName { get; private set; }
        public Statement FunctionBody { get; private set; }

        public FunctionDefinitionStatement(Identifier fcnName, Identifier[] returnList, Identifier[] parameterList, Statement functionBody)
            : base()
        {
            FcnName = fcnName;
            ReturnList = returnList;
            ParameterList = parameterList;
            FunctionBody = functionBody;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    // primer:
    //    global x y
    //    new GlobalDeclarationStatement(new Identifier("x"), new Identifier("y"))
    public class GlobalDeclarationStatement : Statement
    {
        public Identifier[] DeclArray { get; private set; }

        public GlobalDeclarationStatement(params Identifier[] declArray)
            : base()
        {
            DeclArray = declArray;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }


    // primer:
    //    persistent x y
    //    new PersistentDeclarationStatement(new Identifier("x"), new Identifier("y"))
    // napomena: dozvoljeno samo u m - fajlovima
    public class PersistentDeclarationStatement : Statement
    {
        public Identifier[] DeclArray { get; private set; }

        public PersistentDeclarationStatement(params Identifier[] declArray)
            : base()
        {
            DeclArray = declArray;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

}
